﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using Boardgame;
using BoardgameModelViewed;
using WinChessController;
using WinGameControls;


namespace WinChessView
{
    static class WinProgram
    {
        [STAThread]
        static void Main ()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault (false);
            Application.Run (new ChessController (new ChessViewFactory()));
        }
    }


    internal class ChessViewFactory : IChessViewFactory
    {
        public void Make (ChessController controller, ChessModelBase modelBase)
        {
            var view = new ChessView (controller, modelBase);
        }
    }


    public partial class ChessView : IChessView
    {
        static private Icon[][] pieceIcon = new Icon[][]
        { new Icon[]
          { null,
            global::WinChessController.Properties.Resources.WhiteKing,
            global::WinChessController.Properties.Resources.WhiteQueen,
            global::WinChessController.Properties.Resources.WhiteRook,
            global::WinChessController.Properties.Resources.WhiteBishop,
            global::WinChessController.Properties.Resources.WhiteKnight,
            global::WinChessController.Properties.Resources.WhitePawn
          },
          new Icon[]
          { null,
            global::WinChessController.Properties.Resources.BlackKing,
            global::WinChessController.Properties.Resources.BlackQueen,
            global::WinChessController.Properties.Resources.BlackRook,
            global::WinChessController.Properties.Resources.BlackBishop,
            global::WinChessController.Properties.Resources.BlackKnight,
            global::WinChessController.Properties.Resources.BlackPawn
          }
        };

        private ChessController controller;
        private ChessModelBase modelBase;

        #region Constructors

        internal ChessView (ChessController winController, ChessModelBase modelBase)
        {
            this.controller = winController;
            this.modelBase = modelBase;

            this.modelBase.SetView (this);

            this.modelBase.GameCreated += ShowNewGame;
            this.modelBase.StatusUpdate += UpdateStatus;
            this.modelBase.TokenRemove += RemoveToken;
            this.modelBase.TokenPlace += PlaceToken;
            this.modelBase.MoveProcess += ProcessCompletedMove;
            this.modelBase.UndoPreview += RemoveMove;

            this.modelBase.HiliteChange += controller.checkerboard.SetHilite;
            this.modelBase.HilitesClear += controller.checkerboard.ClearHilites;

            ShowNewGame();
            UpdateStatus();
        }

        #endregion

        #region IChessView implementation

        public void ShowMessage (string message, Player toPlayer)
        {
            WinMessageBox.Show
            (
                controller.Icon,
                message,
                "Message to " + ChessModelBase.PlayerName (toPlayer),
                MessageBoxButtons.OK
            );
        }


        public bool ShowQuestion (string message, Player toPlayer)
        {
            DialogResult answer = WinMessageBox.Show
            (
                controller.Icon,
                message,
                "Message to " + ChessModelBase.PlayerName (toPlayer),
                MessageBoxButtons.YesNo
            );

            return answer == DialogResult.OK || answer == DialogResult.Yes;
        }

        #endregion

        #region Model event handlers

        private void ShowNewGame ()
        {
            controller.moveList.Items.Clear();

            for (int cy = 0; cy < modelBase.Board.SizeY; ++cy)
                for (int cx = 0; cx < modelBase.Board.SizeX; ++cx)
                {
                    Piece piece = modelBase.Board[cx,cy] as Piece;
                    if (piece != null)
                        PlaceToken (cx, cy, piece.Side, piece.Token);
                    else
                        RemoveToken (cx, cy);
                }
        }


        private void UpdateStatus ()
        {
            controller.promoList.Text = modelBase.CurrentPlayerPromotionName;
            string[] list = modelBase.GetStatusText();

            controller.turn.Text = list[0];
            controller.status1.Text = list[1];
            controller.status2.Text = list[2];

            UpdateEnables();
        }


        private void UpdateEnables ()
        {
            controller.gameMenuResign.Enabled = modelBase.IsUnderway;
            controller.gameMenuUndo.Enabled = modelBase.IsUnderway && modelBase.Plies.Count > 0;
            controller.drawMenu.Enabled = modelBase.IsUnderway;
            controller.drawMenuFiftyMoves.Enabled = modelBase.IsUnderway && modelBase.IsFiftyMoveRuleClaimable;
            controller.drawMenuThreefoldRepNow.Enabled = modelBase.IsUnderway && modelBase.IsThreefoldRepRuleClaimable;
            controller.drawMenuThreefoldRepAfter.Checked = modelBase.IsUnderway && modelBase.IsThreefoldRepDrawOnMoveRequested;
            controller.drawMenuRequest.Enabled = modelBase.IsUnderway;

            controller.checkerboard.Enabled = modelBase.IsUnderway;

            controller.promoList.Enabled = modelBase.IsUnderway;
        }


        private void RemoveToken (int cx, int cy)
        {
            controller.checkerboard.SetIcon (cx, cy, null);
        }


        private void PlaceToken (int cx, int cy, Player player, Token token)
        {
            controller.checkerboard.SetIcon (cx, cy, pieceIcon[(int) player][(int) token]);
        }


        private void ProcessCompletedMove ()
        {
            int lastItem;
            Ply ply = modelBase.Plies.Top;
            string newText = ply.ToString();

            controller.checkerboard.ClearSelection();

            if (ply.Moving.Side == Player.Black)
            {
                lastItem = controller.moveList.Items.Count - 1;
                string text = (string) controller.moveList.Items[lastItem];
                controller.moveList.Items[lastItem] = text + "  " + newText;
            }
            else
            {
                int turnNumber = modelBase.Plies.Count / 2 + 1;
                lastItem = controller.moveList.Items.Count;
                controller.moveList.Items.Add (turnNumber.ToString() + ".  " + newText);
            }

            controller.moveList.Focus();
            controller.moveList.SetSelected (controller.moveList.Items.Count - 1, true);
        }


        private void RemoveMove ()
        {
            int lastItem = (modelBase.Plies.Count - 1) / 2;
            if (modelBase.Plies.Count % 2 == 0)
                controller.moveList.Items[lastItem] = (lastItem+1).ToString() + ".  "
                                            + modelBase.Plies[modelBase.Plies.Count-2].ToString();
            else
                controller.moveList.Items.RemoveAt (lastItem);
        }

        #endregion
    }
}
